iT邦幫忙

2021 iThome 鐵人賽

DAY 8
0

我們現在有了許多的基礎的 parser function 了,我們直接來看怎麼樣組合這些 function 來 parse 一些東西吧!以 library 裡面的 Android parser 為例,我們的目標是拿到 RSS 2.0 標準格式裡的 channel 資料。首先,我們先定義 channel 長的樣子包在一個 data class 裡面,而這個 data class 叫做 RssStandardChannelData ,完整的 data class 可以參考這個連結,這邊就不把完整程式碼貼上來了。Channel 裡面又有包含一些資料,我們就可以定義在另一個 data class 裡面,像是 category 、 item 和 cloud 等等。

接著,我們就可以來寫 channel 的 parser function 。

@Throws(IOException::class, XmlPullParserException::class)
private fun XmlPullParser.readRssStandardChannel(): RssStandardChannelData {
    require(XmlPullParser.START_TAG, null, CHANNEL)

		// 1
    var title: String? = null
    var image: Image? = null
    val categories = mutableListOf<Category>()
    var cloud: Cloud? = null
    var textInput: TextInput? = null
    var skipHours: List<Int>? = null
    val items = mutableListOf<RssStandardItemData>()
		// 省略其他變數宣告

		// 2
    while (next() != XmlPullParser.END_TAG) {
        if (eventType != XmlPullParser.START_TAG) continue

				// 3
        when (name) {
            TITLE -> title = readString(TITLE)
            IMAGE -> image = readImage()
            CATEGORY -> categories.add(readCategory())
            CLOUD -> cloud = readCloud()
            TTL -> ttl = readString(TTL)?.toIntOrNull()
            RATING -> rating = readString(RATING)
            TEXT_INPUT -> textInput = readTextInput()
            SKIP_HOURS -> skipHours = readSkipHours()
            ITEM -> items.add(readRssStandardItem())
						// 省略其他處理
            else -> skip()
        }
    }
    require(XmlPullParser.END_TAG, null, CHANNEL)
		// 4
    return RssStandardChannelData(...)
}

在這個 function 裡,我把他分成四個部分來講解,分別對應上方程式碼註解上的數字:

  1. 這邊宣告一些 channel 裡面有的變數,全部都是 nullable type ,因為實際的 XML 裡面,不一定會包含每個值或屬性。另外,在前幾篇有提到 event-based 的機制本身不支援跨層去存取 tag ,所以這邊我們把它們的值存在外面的變數,等到全部數值都處理完畢之後再放到 data class 裡面回傳。
  2. 把 channel tag 內的 event 一個一個拉出來。
  3. 按照 tag 的名稱分別做對應的處理,如果是只有取單一值,可以用 readString 之後再轉成想要的型別。如果 tag 還有另一個 tag ,可以再額外定義一個 data class 來代表該子 tag 。如果 tag 名稱不在處理的範圍,則可以呼叫 skip 去跳過該 tag 。在處理的過程中,有呼叫一些其他的 function ,像是 readCategory readTextInput readSkipHours 和 readRssStandardItem 等,它們內部處理的邏輯是和 readRssStandardChannel 相同,這些 function 可以在這邊找到。
  4. 最後,把所有的變數收集起來放到 data class 裡面去產出資料,這邊因為變數太多,忽略了一些變數。完整版的程式碼可以到這裡看。

現在,我們掌握了使用原生的 XmlPullParser 的方法,可以組合出我們想要的資料 parser ,但別高興得太早!上一段程式碼是不是看起來有哪邊怪怪的?假設我們有很多種的資料型態和 tag 要取資料,那我們不就要每一種都寫一個 function 去處理?如果我們有方法可以去產生這些程式碼,我們不用自己手動寫。這個就是我們的 annotation processor 可以辦得到的事,下篇開始會講 annotation 和 annotation processor !


上一篇
使用 XmlPullParser (二)
下一篇
Annotation 介紹
系列文
如何使用 Kotlin Annotation Processor 做出自己的 Custom Data Parser Library30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言